package guggaTests.utils
{
	import flash.events.Event;
	
	import flexunit.framework.TestCase;
	
	import gugga.eventHelpers.EventDescriptor;
	import gugga.eventHelpers.Listener;
	import gugga.tasks.FictiveTask;
	import gugga.tasks.events.TaskEvent;

	public class ListenerTest extends TestCase
	{
		private var isEventRaised:Boolean;
		private var eventRaisedCount:Number;
		
		private var mMergedObject : Object;
		
		// variables need for the merging object test:
		private var dataProperty1:String = "dataProperty1";
		private var dataProperty1Value:String = "dataProperty1Value";
		private var dataProperty2:String = "dataProperty2";
		private var dataProperty2Value:String = "dataProperty2Value";
		
		public function ListenerTest(methodName:String=null)
		{
			super(methodName);
			
			isEventRaised = false;
			eventRaisedCount = 0;
			mMergedObject = null;
		}
				
		public function testConstructor() : void
		{
			this.reset();
			
			var fictiveEventSource:FictiveTask = new FictiveTask();
			var eventDescriptor:EventDescriptor = new EventDescriptor(fictiveEventSource, TaskEvent.COMPLETED);
					
			var dataObject:Object = new Object();
			
			var isListeningOnlyOnce:Boolean = false;
			
			var listener:Listener = new Listener(
					eventDescriptor, 
					onEventRaised, 
					dataObject, 
					isListeningOnlyOnce);
			
			assertNotNull(
					"listener should not be null after creation", 
					listener);
			assertNotUndefined(
					"listener should not be undefined after creation", 
					listener);
			
			assertFalse(
					"listener should not listen right after creation, use start() should to start listening", 
					listener.Listening);
		}
		
		public function testCreate() : void
		{
			this.reset();
			
			var fictiveEventSource:FictiveTask = new FictiveTask();
			var eventDescriptor:EventDescriptor = new EventDescriptor(fictiveEventSource, TaskEvent.COMPLETED);
					
			var dataObject:Object = new Object();
			
			var isListeningOnlyOnce:Boolean = false;
			
			var listener:Listener = Listener.create(
					eventDescriptor, 
					onEventRaised, 
					dataObject, 
					isListeningOnlyOnce);
			
			assertNotNull("listener should not be null after creation", listener);
			assertNotUndefined("listener should not be undefined after creation", listener);
			
			assertTrue(
					"listener should be listening after create(), create() calls start()", 
					listener.Listening);
			
			// raise "completed" event:
			fictiveEventSource.start();
			
			assertTrue(
					"event should be caught and consumed", 
					this.isEventRaised);
			
			// listener is not listening only once, so the following event should 
			// be caught too:
			fictiveEventSource.start();
			assertEquals(
					"this is not a single time listener, second event should be caught and consumed too",
					2, 
					this.eventRaisedCount);
		}
		
		public function testCreateSingleTimeListener() : void
		{
			this.reset();
			
			var fictiveEventSource:FictiveTask = new FictiveTask();
			var eventDescriptor:EventDescriptor = new EventDescriptor(fictiveEventSource, TaskEvent.COMPLETED);
			
			var listener:Listener = Listener.createSingleTimeListener(eventDescriptor, onEventRaised);
			
			assertNotNull("listener should not be null after creation", listener);
			assertNotUndefined("listener should not be undefined after creation", listener);
			
			assertTrue(
					"listener should be listening after create(), create() calls start()", 
					listener.Listening);
			
			// raise "completed" event:
			fictiveEventSource.start();
			
			assertTrue("event should be caught and consumed", isEventRaised);
			
			// listener is listening only once, so the following event should not 
			// be caught:
			fictiveEventSource.start();
			assertEquals(
					"this is a single time listener, second event should not be caught",
					1, 
					this.eventRaisedCount);
		}
		
		public function testCreateMergingListener() : void
		{
			this.reset();
			
			var fictiveEventSource:FictiveTask = new FictiveTask();
			var eventDescriptor:EventDescriptor = new EventDescriptor(fictiveEventSource, TaskEvent.COMPLETED);
			
			var dataObject:Object = new Object();
			
			var listener:Listener = Listener.createDataForwardingListener(eventDescriptor, onEventRaised, dataObject);
			
			assertNotNull("listener should not be null after creation", listener);
			assertNotUndefined("listener should not be undefined after creation", listener);
			
			assertTrue(
					"listener should be listening after create(), create() calls start()", 
					listener.Listening);
			
			// raise "completed" event:
			fictiveEventSource.start();
			
			assertTrue(
					"event should be caught and consumed", 
					isEventRaised);
			
			// listener is not listening only once, so the following event should 
			// be caught too:
			fictiveEventSource.start();
			assertEquals(
					"this is not a single time listener, second event should be caught and consumed too",
					2, 
					eventRaisedCount);
		}
		
		public function testCreateSingleTimeMergingListener() : void
		{
			this.reset();
			
			var fictiveEventSource:FictiveTask = new FictiveTask();
			var eventDescriptor:EventDescriptor = new EventDescriptor(fictiveEventSource, TaskEvent.COMPLETED);
			
			var dataObject:Object = new Object();
			
			var listener:Listener = Listener.createSingleTimeDataForwardingListener(
					eventDescriptor, 
					onEventRaised,
					dataObject);
			
			assertNotNull("listener should not be null after creation", listener);
			assertNotUndefined("listener should not be undefined after creation", listener);
			
			assertTrue(
					"listener should be listening after create(), create() calls start()", 
					listener.Listening);
			
			// raise "completed" event:
			fictiveEventSource.start();
			
			assertTrue(
					"event should be caught and consumed", 
					this.isEventRaised);
			
			// listener is listening only once, so the following event should not 
			// be caught:
			fictiveEventSource.start();
			assertEquals(
					"this is a single time listener, second event should not be caught",
					1, 
					this.eventRaisedCount);
		}
		
		public function testHandleEventObjectMerging() : void
		{
			this.reset();
			
			var fictiveEventSource:FictiveTask = new FictiveTask();
			var eventDescriptor:EventDescriptor = new EventDescriptor(fictiveEventSource, TaskEvent.COMPLETED);
			
			var dataObject:Object = new Object();
			dataObject[dataProperty1] = dataProperty1Value;
			dataObject[dataProperty2] = dataProperty2Value;
			
			var listener:Listener = Listener.createDataForwardingListener(
					eventDescriptor, 
					onEventRaisedAssertMergedObject,
					dataObject);
			
			// raise "completed" event:
			fictiveEventSource.start();
			
			assertNotNull(
					"the merged object should have dataProperty1 property that's not null", 
					mMergedObject[this.dataProperty1]);
			assertNotUndefined(
					"the merged object should have dataProperty1 property that's not undefined", 
					mMergedObject[this.dataProperty1]);
			assertEquals(
					"dataProperty1's value should be " + this.dataProperty1Value, 
					this.dataProperty1Value, 
					mMergedObject[this.dataProperty1]);
			
			assertNotNull(
					"the merged object should have dataProperty2 property that's not null", 
					mMergedObject[this.dataProperty2]);
			assertNotUndefined(
					"the merged object should have dataProperty2 property that's not undefined", 
					mMergedObject[this.dataProperty2]);
			assertEquals(
					"dataProperty2's value should be " + this.dataProperty2Value, 
					this.dataProperty2Value, 
					mMergedObject[this.dataProperty2]);
		}
		
		private function onEventRaised(aEvent : Object, aData : Object = null) : void
		{
			this.isEventRaised = true;
			this.eventRaisedCount++;
		}
		
		private function onEventRaisedAssertMergedObject(aEvent : Object, aData : Object) : void
		{
			mMergedObject = aData;
		}
		
		private function reset() : void
		{
			this.isEventRaised = false;
			this.eventRaisedCount = 0;
		}
		
	}
}